package com.musichord.core;

import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiEvent;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.Track;

import com.musichord.core.event.MCEvent;

public class CoreHelper {
	public static final int TEMPO_CHANGE = 0x51;
	public static final int METER_CHANGE = 0x58;
	public static int DEFAULT_VELOCITY = 100;

	private CoreHelper() {
	}

	/** Add MIDI events with relative ticks to a specific tick in the track */
	public static void addEvents2TrackAt(Track track, List<MidiEvent> midiEvents,
			long tick) {
		for (MidiEvent midiEvent : midiEvents) {
			midiEvent.setTick(midiEvent.getTick() + tick);
			track.add(midiEvent);
		}
	}

	/** Add ordered MIDI events to the end of the track */
	public static void addEvents2Track(Track track, List<MidiEvent> midiEvents) {
		addEvents2TrackAt(track, midiEvents, track.ticks());
	}

	/** Add one MCEvent to a specific tick in the track */
	public static void addMCEvent2TrackAt(Track track, MCEvent event, long tick) {
		for (MidiEvent midiEvent : event.getMidiEvents()) {
			midiEvent.setTick(midiEvent.getTick() + tick);
			track.add(midiEvent);
		}
	}

	/** Add one MCEvent to the end of the track */
	public static void addMCEvent2Track(Track track, MCEvent event) {
		addEvents2TrackAt(track, event.getMidiEvents(), track.ticks());
	}

	/** Add unordered MCEvents to the end of the track one by one */
	public static void addMCEvents2Track(Track track, List<MCEvent> events) {
		for (MCEvent event : events) {
			addMCEvent2Track(track, event);
		}
	}

	/* ========================================================================= */

	public static void Write2File(Sequence sequence, String filePath) {
		File file = new File(filePath);
		try {
			file.createNewFile();
			MidiSystem.write(sequence, 1, file);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void playSequence(Sequence sequence)
			throws MidiUnavailableException, InvalidMidiDataException,
			InterruptedException {
		Sequencer sequencer = MidiSystem.getSequencer(true);
		sequencer.setSequence(sequence);
		sequencer.open();
		sequencer.start();
		while (sequencer.isRunning()) {
			Thread.sleep(100);
		}
		sequencer.stop();
		sequencer.close();
	}
}
